Assignment 1. Perception Visualization
olive <- read.csv("olive.csv", sep = ",", header = TRUE)
library(ggplot2)
library(plotly)
library(MASS)
library(gridExtra)
p_vs_o <- ggplot(olive, aes(x=oleic, y=palmitic,
color = linolenic)) +
geom_point()
#xlab("")
p_vs_o

olive$linolenic2 <- cut_interval(olive$linolenic, n=4)
p_vs_o2 <- ggplot(olive, aes(x=oleic, y=palmitic, color = linolenic2)) +
geom_point()
p_vs_o2

pal_vs_ole_col <- ggplot(olive, aes(palmitic, oleic)) +
geom_point(aes(color=linolenic2))
pal_vs_ole_col

pal_vs_ole_size <- ggplot(olive, aes(palmitic, oleic)) +
geom_point(aes(size=linolenic2))
pal_vs_ole_size

pal_vs_ole_angle <- ggplot(olive, aes(palmitic, oleic)) +
geom_point() +
geom_spoke(aes(angle=as.numeric(linolenic2),radius=20))
pal_vs_ole_angle

o_vs_e <- ggplot(olive, aes(x=oleic, y=eicosenoic, color = Region)) +
geom_point()
o_vs_e

o_vs_e0 <- ggplot(olive, aes(x=oleic, y = eicosenoic, color = as.factor(Region)))+
geom_point()
o_vs_e0

olive$linoleic2 <- cut_interval(olive$linoleic, n=3)
olive$palmitic2 <- cut_interval(olive$palmitic, n=3)
olive$palmitoleic2 <- cut_interval(olive$palmitoleic, n=3)
o_vs_e1 <- ggplot(olive, aes(x=oleic, y=eicosenoic)) +
geom_point(aes(color=linoleic2, size=palmitoleic2, shape=palmitic2))
o_vs_e1

o_vs_e2 <- ggplot(olive, aes(x=oleic, y=eicosenoic)) +
geom_point(aes(color=Region, size=palmitoleic2, shape=palmitic2))
o_vs_e2

plot_ly(data = olive, labels=~Area, type = 'pie', showlegend = F) %>%
layout(title = 'Proportion of Oils from different regions',
xaxis = list(showgrid = F, zeroline = F, showticklables = F),
yaxis = list(showgrid = F, zeroline = F, showticklables = F))
l_vs_e <- ggplot(olive, aes(x = linoleic, y = eicosenoic)) +
geom_point() +
geom_density_2d()#+
#stat_density_2d(aes(fill = stat(level)), geom = "polygon")
l_vs_e

Assignment 2: Multidimensional Scaling of a high-dimensional object
# reading the data
baseball <- read.csv("baseball-2016.csv", sep = ",", header = TRUE)
Question1
The xlsx file is converted to a csv file, makes it easier to load the data without extra packages. It is reasonable to scale the data because they have different ranges so that features with large scales do not dominate. Example, comparing maximum value and minimum value for “AB” and “Home runs per game”. The two are on totally different scales.
# range of AB
range1 <- max(baseball$AB) - min(baseball$AB)
range1
[1] 340
# range of HR per game
range2 <- max(baseball$HR.per.game) - min(baseball$HR.per.game)
range2
[1] 0.8039644
The density plot below graphically explains why scaling is needed. Appropriate density should be similar to log normal density.
rr plot(density(as.matrix(baseball[3:ncol(baseball)])))

Question 2
# scale the 26 numeric columns
baseball2 <- scale(baseball[ ,3:ncol(baseball)])
# Getting distance between points using Minkowski
mink_d <- dist(baseball2, method = "minkowski", p =2)
# get 2 column vector with fitted configuration
resid <- isoMDS(mink_d, k=2 )
initial value 19.856833
iter 5 value 16.319153
iter 10 value 16.046215
final value 15.935476
converged
# getting the coordinates
coords <- resid$points
# convert coords to dataframe
coordsMDS <- as.data.frame(coords)
# cbind to get column Team and League
coordsMDS2 <- cbind(baseball[ , 1:2], coordsMDS)
# plot the new dimension and color by League
plot_ly(coordsMDS2, x= ~V1, y = ~V2, type ="scatter", hovertext = ~ Team,
color = ~League, colors = c("#0444BF","#F46A4E"))
There appears to be a difference between the two leagues; most of the NL league teams are on the second and third quadrant (negative V2) while most of the AL league teams are on the first and fourth quadrant (positive V2). The y-axis “V2” has the best differentation between the leagues. The Boston Red Sox, Atlanta Braves and Philadelphia Philies appear to be outliers.
rr # Shepard diagrams assess the goodness-of-fit of MDS techniques # run shep on points from isoMDS and using same distance calculated in previous step shep <- Shepard(mink_d, coords)
# convert the distance to numeric
delta <- as.numeric(mink_d)
# possibly a matrix of the coords
D <- as.numeric(dist(coords))
# create a square matrix with dimensions from the rows of coords
# n as rows
n = nrow(coords)
# index as empyt matrix
index <- matrix(1:n, nrow = n, ncol = n)
# get index of the lower triangle of the index matrix and convert it to numeric
index1 <- as.numeric(index[lower.tri(index)])
# same procedur
n = nrow(coords)
index=matrix(1:n, nrow=n, ncol=n, byrow = T)
index2=as.numeric(index[lower.tri(index)])
# plotly
plot_ly()%>%
add_markers(x=~delta, y=~D, hoverinfo = 'text',
text = ~paste('Obj1: ', rownames(baseball)[index1],
'<br> Obj 2: ', rownames(baseball)[index2])) #%>%
#if nonmetric MDS inolved
#add_lines(x=~sh$x, y=~sh$yf)
rr # get MDS variable V2 and cbind with points from isoMDS d4 <- cbind(baseball[ ,1:2], coords[,2], baseball2[,])
rename col3 to V2
colnames(d4)[3] <- c(2)
rr # function to successively get plots of V2 vs other variables myplot <-function(df, y_string){ ggplot(df, aes_string(x = 2, y = y_string, color = ))+ geom_point()+ geom_vline(xintercept = 0, color = )+ geom_hline(yintercept = 0, color = ) }
rr # Variables that seem to have strongest postive relationship # HR per game: myplot(d4, .per.game)
rr # HR myplot(d4, 3B)
Per the plot, HR per game and HR have the same scatter points. The two have strongest positve connection to V2 while X3B has the strongest negative connection to V2.
LS0tDQp0aXRsZTogIlZpc3VhbGl6YXRpb24gTGFiIDIiDQphdXRob3I6ICJSb3NobmkgU3VuZGFyYW11cnRoeSAocm9zc3U4MDkpOyBCcmlhbiBNYXNpbmRlIChicmltYTc0OCkiDQpkYXRlOiAiMTcgU2VwdGVtYmVyIDIwMTgiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdGhlbWU6IGpvdXJuYWwNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCmZvbnRzaXplOiAxMXB0DQotLS0NCg0KIyMjIEFzc2lnbm1lbnQgMS4gUGVyY2VwdGlvbiBWaXN1YWxpemF0aW9uDQoNCmBgYHtyIGRhdGF9DQpvbGl2ZSA8LSByZWFkLmNzdigib2xpdmUuY3N2Iiwgc2VwID0gIiwiLCBoZWFkZXIgPSBUUlVFKQ0KYGBgDQoNCmBgYHtyIGxpYnJhcmllcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoTUFTUykNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KYGBgDQoNCmBgYHtyIHF1ZXN0aW9uMV9hfQ0KcF92c19vIDwtIGdncGxvdChvbGl2ZSwgYWVzKHg9b2xlaWMsIHk9cGFsbWl0aWMsDQogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGxpbm9sZW5pYykpICsNCiAgZ2VvbV9wb2ludCgpIA0KICAjeGxhYigiIikNCnBfdnNfbw0KYGBgDQoNCmBgYHtyIGN1dF9pbnRlcnZhbH0NCm9saXZlJGxpbm9sZW5pYzIgPC0gY3V0X2ludGVydmFsKG9saXZlJGxpbm9sZW5pYywgbj00KQ0KYGBgDQoNCg0KYGBge3IgcXVlc3Rpb24xX2J9DQpwX3ZzX28yIDwtIGdncGxvdChvbGl2ZSwgYWVzKHg9b2xlaWMsIHk9cGFsbWl0aWMsIGNvbG9yID0gbGlub2xlbmljMikpICsgDQogIGdlb21fcG9pbnQoKQ0KDQpwX3ZzX28yDQpgYGANCg0KYGBge3IgcXVlc3Rpb24gMl9hLCB3YXJuaW5nPUZBTFNFfQ0KcGFsX3ZzX29sZV9jb2wgPC0gZ2dwbG90KG9saXZlLCBhZXMocGFsbWl0aWMsIG9sZWljKSkgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvcj1saW5vbGVuaWMyKSkNCg0KcGFsX3ZzX29sZV9jb2wNCmBgYA0KDQoNCmBgYHtyIHF1ZXN0aW9uIDJfYiwgd2FybmluZyA9IEZBTFNFfQ0KcGFsX3ZzX29sZV9zaXplIDwtIGdncGxvdChvbGl2ZSwgYWVzKHBhbG1pdGljLCBvbGVpYykpICsNCiAgZ2VvbV9wb2ludChhZXMoc2l6ZT1saW5vbGVuaWMyKSkNCg0KcGFsX3ZzX29sZV9zaXplDQpgYGANCg0KYGBge3IgcXVlc3Rpb24gMl9jLCB3YXJuaW5nPUZBTFNFfQ0KcGFsX3ZzX29sZV9hbmdsZSA8LSBnZ3Bsb3Qob2xpdmUsIGFlcyhwYWxtaXRpYywgb2xlaWMpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc3Bva2UoYWVzKGFuZ2xlPWFzLm51bWVyaWMobGlub2xlbmljMikscmFkaXVzPTIwKSkNCg0KcGFsX3ZzX29sZV9hbmdsZQ0KYGBgDQoNCmBgYHtyIFF1ZXN0aW9uM30NCm9fdnNfZSA8LSBnZ3Bsb3Qob2xpdmUsIGFlcyh4PW9sZWljLCB5PWVpY29zZW5vaWMsIGNvbG9yID0gUmVnaW9uKSkgKyANCiAgZ2VvbV9wb2ludCgpDQpvX3ZzX2UNCmBgYA0KDQpgYGB7ciBxdWVzdGlvbjNfYn0NCm9fdnNfZTAgPC0gZ2dwbG90KG9saXZlLCBhZXMoeD1vbGVpYywgeSA9IGVpY29zZW5vaWMsIGNvbG9yID0gYXMuZmFjdG9yKFJlZ2lvbikpKSsNCiAgZ2VvbV9wb2ludCgpDQoNCm9fdnNfZTANCmBgYA0KDQoNCmBgYHtyIGRpc2NyZXRpemF0aW9ufQ0Kb2xpdmUkbGlub2xlaWMyIDwtIGN1dF9pbnRlcnZhbChvbGl2ZSRsaW5vbGVpYywgbj0zKQ0Kb2xpdmUkcGFsbWl0aWMyIDwtIGN1dF9pbnRlcnZhbChvbGl2ZSRwYWxtaXRpYywgbj0zKQ0Kb2xpdmUkcGFsbWl0b2xlaWMyIDwtIGN1dF9pbnRlcnZhbChvbGl2ZSRwYWxtaXRvbGVpYywgbj0zKQ0KYGBgDQoNCmBgYHtyIHF1ZXN0aW9uNCwgd2FybmluZz1GQUxTRX0NCm9fdnNfZTEgPC0gZ2dwbG90KG9saXZlLCBhZXMoeD1vbGVpYywgeT1laWNvc2Vub2ljKSkgKyANCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9bGlub2xlaWMyLCBzaXplPXBhbG1pdG9sZWljMiwgc2hhcGU9cGFsbWl0aWMyKSkNCm9fdnNfZTENCmBgYA0KDQpgYGB7ciBxdWVzdGlvbjUsIHdhcm5pbmc9RkFMU0V9DQpvX3ZzX2UyIDwtIGdncGxvdChvbGl2ZSwgYWVzKHg9b2xlaWMsIHk9ZWljb3Nlbm9pYykpICsgDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yPVJlZ2lvbiwgc2l6ZT1wYWxtaXRvbGVpYzIsIHNoYXBlPXBhbG1pdGljMikpDQoNCm9fdnNfZTINCmBgYA0KDQpgYGB7ciBxdWVzdGlvbjZ9DQpwbG90X2x5KGRhdGEgPSBvbGl2ZSwgbGFiZWxzPX5BcmVhLCB0eXBlID0gJ3BpZScsIHNob3dsZWdlbmQgPSBGKSAlPiUNCiAgbGF5b3V0KHRpdGxlID0gJ1Byb3BvcnRpb24gb2YgT2lscyBmcm9tIGRpZmZlcmVudCByZWdpb25zJywNCiAgICAgICAgeGF4aXMgPSBsaXN0KHNob3dncmlkID0gRiwgemVyb2xpbmUgPSBGLCBzaG93dGlja2xhYmxlcyA9IEYpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHNob3dncmlkID0gRiwgemVyb2xpbmUgPSBGLCBzaG93dGlja2xhYmxlcyA9IEYpKQ0KDQpgYGANCg0KYGBge3IgcXVlc3Rpb243fQ0KbF92c19lIDwtIGdncGxvdChvbGl2ZSwgYWVzKHggPSBsaW5vbGVpYywgeSA9IGVpY29zZW5vaWMpKSArDQogIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX2RlbnNpdHlfMmQoKSMrDQogICNzdGF0X2RlbnNpdHlfMmQoYWVzKGZpbGwgPSBzdGF0KGxldmVsKSksIGdlb20gPSAicG9seWdvbiIpDQpsX3ZzX2UgIA0KYGBgDQoNCiMjIyBBc3NpZ25tZW50IDI6IE11bHRpZGltZW5zaW9uYWwgU2NhbGluZyBvZiBhIGhpZ2gtZGltZW5zaW9uYWwgb2JqZWN0DQoNCmBgYHtyfQ0KIyByZWFkaW5nIHRoZSBkYXRhDQpiYXNlYmFsbCA8LSByZWFkLmNzdigiYmFzZWJhbGwtMjAxNi5jc3YiLCBzZXAgPSAiLCIsIGhlYWRlciA9IFRSVUUpDQpgYGANCg0KIyMjIyBRdWVzdGlvbjENClRoZSB4bHN4IGZpbGUgaXMgY29udmVydGVkIHRvIGEgY3N2IGZpbGUsIG1ha2VzIGl0IGVhc2llciB0byBsb2FkIHRoZSBkYXRhIHdpdGhvdXQgZXh0cmEgcGFja2FnZXMuIEl0IGlzIHJlYXNvbmFibGUgdG8gc2NhbGUgdGhlIGRhdGEgYmVjYXVzZSB0aGV5IGhhdmUgZGlmZmVyZW50IHJhbmdlcyBzbyB0aGF0IGZlYXR1cmVzIHdpdGggbGFyZ2Ugc2NhbGVzIGRvIG5vdCBkb21pbmF0ZS4gRXhhbXBsZSwgY29tcGFyaW5nIG1heGltdW0gdmFsdWUgYW5kIG1pbmltdW0gdmFsdWUgZm9yICJBQiIgYW5kICJIb21lIHJ1bnMgcGVyIGdhbWUiLiBUaGUgdHdvIGFyZSBvbiB0b3RhbGx5IGRpZmZlcmVudCBzY2FsZXMuDQoNCmBgYHtyfQ0KIyByYW5nZSBvZiBBQg0KcmFuZ2UxIDwtIG1heChiYXNlYmFsbCRBQikgLSAgbWluKGJhc2ViYWxsJEFCKQ0KcmFuZ2UxDQpgYGANCg0KYGBge3J9DQojIHJhbmdlIG9mIEhSIHBlciBnYW1lDQpyYW5nZTIgPC0gbWF4KGJhc2ViYWxsJEhSLnBlci5nYW1lKSAtIG1pbihiYXNlYmFsbCRIUi5wZXIuZ2FtZSkNCg0KcmFuZ2UyDQpgYGANCg0KVGhlIGRlbnNpdHkgcGxvdCBiZWxvdyBncmFwaGljYWxseSBleHBsYWlucyB3aHkgc2NhbGluZyBpcyBuZWVkZWQuIEFwcHJvcHJpYXRlIGRlbnNpdHkgc2hvdWxkIGJlIHNpbWlsYXIgdG8gbG9nIG5vcm1hbCBkZW5zaXR5Lg0KYGBge3IgYmFzZV9kZW5zaXR5fQ0KcGxvdChkZW5zaXR5KGFzLm1hdHJpeChiYXNlYmFsbFszOm5jb2woYmFzZWJhbGwpXSkpKQ0KYGBgDQoNCg0KIyMjIyBRdWVzdGlvbiAyDQoNCmBgYHtyfQ0KIyBzY2FsZSB0aGUgMjYgbnVtZXJpYyBjb2x1bW5zDQpiYXNlYmFsbDIgPC0gc2NhbGUoYmFzZWJhbGxbICwzOm5jb2woYmFzZWJhbGwpXSkNCmBgYA0KDQpgYGB7cn0NCiMgR2V0dGluZyBkaXN0YW5jZSBiZXR3ZWVuIHBvaW50cyB1c2luZyBNaW5rb3dza2kNCm1pbmtfZCA8LSBkaXN0KGJhc2ViYWxsMiwgbWV0aG9kID0gIm1pbmtvd3NraSIsIHAgPTIpDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9DQojIGdldCAyIGNvbHVtbiB2ZWN0b3Igd2l0aCBmaXR0ZWQgY29uZmlndXJhdGlvbiANCnJlc2lkIDwtIGlzb01EUyhtaW5rX2QsIGs9MiApDQoNCiMgZ2V0dGluZyB0aGUgY29vcmRpbmF0ZXMNCmNvb3JkcyA8LSByZXNpZCRwb2ludHMNCg0KIyBjb252ZXJ0IGNvb3JkcyB0byBkYXRhZnJhbWUNCmNvb3Jkc01EUyA8LSBhcy5kYXRhLmZyYW1lKGNvb3JkcykNCg0KIyBjYmluZCB0byBnZXQgY29sdW1uIFRlYW0gYW5kIExlYWd1ZQ0KY29vcmRzTURTMiA8LSBjYmluZChiYXNlYmFsbFsgLCAxOjJdLCBjb29yZHNNRFMpDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9DQojIHBsb3QgdGhlIG5ldyBkaW1lbnNpb24gYW5kIGNvbG9yIGJ5ICBMZWFndWUNCnBsb3RfbHkoY29vcmRzTURTMiwgeD0gflYxLCB5ID0gflYyLCB0eXBlID0ic2NhdHRlciIsIGhvdmVydGV4dCA9IH4gVGVhbSwNCiAgICAgICAgICAgIGNvbG9yID0gfkxlYWd1ZSwgY29sb3JzID0gYygiIzA0NDRCRiIsIiNGNDZBNEUiKSkNCmBgYA0KDQpUaGVyZSBhcHBlYXJzIHRvIGJlIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gbGVhZ3VlczsgbW9zdCBvZiB0aGUgTkwgbGVhZ3VlIHRlYW1zIGFyZSBvbiB0aGUgc2Vjb25kIGFuZCB0aGlyZCBxdWFkcmFudCAobmVnYXRpdmUgVjIpIHdoaWxlIG1vc3Qgb2YgdGhlIEFMIGxlYWd1ZSB0ZWFtcyBhcmUgb24gdGhlIGZpcnN0IGFuZCBmb3VydGggcXVhZHJhbnQgKHBvc2l0aXZlIFYyKS4gVGhlIHktYXhpcyAiVjIiIGhhcyB0aGUgYmVzdCBkaWZmZXJlbnRhdGlvbiBiZXR3ZWVuIHRoZSBsZWFndWVzLiBUaGUgQm9zdG9uIFJlZCBTb3gsIEF0bGFudGEgQnJhdmVzIGFuZCBQaGlsYWRlbHBoaWEgUGhpbGllcyBhcHBlYXIgdG8gYmUgb3V0bGllcnMuDQoNCmBgYHtyIHF1ZXN0aW9uM18yfQ0KIyBTaGVwYXJkIGRpYWdyYW1zIGFzc2VzcyB0aGUgZ29vZG5lc3Mtb2YtZml0IG9mIE1EUyB0ZWNobmlxdWVzDQojIHJ1biBzaGVwIG9uIHBvaW50cyBmcm9tIGlzb01EUyBhbmQgdXNpbmcgc2FtZSBkaXN0YW5jZSBhcyBjYWxjdWxhdGVkIGluIHByZXZpb3VzIHN0ZXANCnNoZXAgPC0gU2hlcGFyZChtaW5rX2QsIGNvb3JkcykNCmBgYA0KDQpgYGB7cn0NCiMgY29udmVydCB0aGUgZGlzdGFuY2UgdG8gbnVtZXJpYw0KZGVsdGEgPC0gYXMubnVtZXJpYyhtaW5rX2QpDQpgYGANCg0KDQpgYGB7cn0NCiMgQWxsIHRoZSBjb29yZHMgaW4gb25lIGNvbHVtbg0KRCA8LSBhcy5udW1lcmljKGRpc3QoY29vcmRzKSkNCmBgYA0KDQpgYGB7cn0NCiMgY3JlYXRlIGEgc3F1YXJlIG1hdHJpeCB3aXRoIGRpbWVuc2lvbnMgZnJvbSB0aGUgcm93cyBvZiBjb29yZHMNCiMgbiBhcyByb3dzIA0KbiA9IG5yb3coY29vcmRzKQ0KDQojIGluZGV4IGFzIGVtcHl0IG1hdHJpeA0KaW5kZXggPC0gbWF0cml4KDE6biwgbnJvdyA9IG4sIG5jb2wgPSBuKQ0KDQojIGdldCBpbmRleCBvZiB0aGUgbG93ZXIgdHJpYW5nbGUgb2YgdGhlIGluZGV4IG1hdHJpeCBhbmQgY29udmVydCBpdCB0byBudW1lcmljDQppbmRleDEgPC0gYXMubnVtZXJpYyhpbmRleFtsb3dlci50cmkoaW5kZXgpXSkNCg0KYGBgDQoNCmBgYHtyfQ0KIyBzYW1lIHByb2NlZHVyDQpuID0gbnJvdyhjb29yZHMpDQoNCmluZGV4IDwtIG1hdHJpeCgxOm4sIG5yb3c9biwgbmNvbD1uLCBieXJvdyA9IFQpDQoNCmluZGV4MiA8LSBhcy5udW1lcmljKGluZGV4W2xvd2VyLnRyaShpbmRleCldKQ0KYGBgDQoNCmBgYHtyfQ0KIyBwbG90bHkNCnBsb3RfbHkoKSU+JQ0KICBhZGRfbWFya2Vycyh4PX5kZWx0YSwgeT1+RCwgaG92ZXJpbmZvID0gJ3RleHQnLA0KICAgICAgICB0ZXh0ID0gfnBhc3RlKCdPYmoxOiAnLCByb3duYW1lcyhiYXNlYmFsbClbaW5kZXgxXSwNCiAgICAgICAgICAgICAgICAgICAgICAnPGJyPiBPYmogMjogJywgcm93bmFtZXMoYmFzZWJhbGwpW2luZGV4Ml0pKSAjJT4lDQogICNpZiBub25tZXRyaWMgTURTIGlub2x2ZWQNCiAgI2FkZF9saW5lcyh4PX5zaCR4LCB5PX5zaCR5ZikNCmBgYA0KDQoNCmBgYHtyIHF1ZXN0aW9uNF8yfQ0KIyBnZXQgTURTIHZhcmlhYmxlIFYyIGFuZCBjYmluZCB3aXRoIHBvaW50cyBmcm9tIGlzb01EUw0KZDQgPC0gY2JpbmQoYmFzZWJhbGxbICwxOjJdLCBjb29yZHNbLDJdLCBiYXNlYmFsbDJbLF0pDQoNCiMgcmVuYW1lIGNvbDMgdG8gVjINCmNvbG5hbWVzKGQ0KVszXSA8LSBjKCJWMiIpDQpgYGANCg0KYGBge3IgZnhuMSwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0NCiMgQ29uc3VsdGVkIE5hdmVlbiBHYWJyaWVsIGZvciB0aGUgZnVuY3Rpb24gdG8gcHJvZHVjZSBzdWNjZXNzaXZlIHNjYXR0ZXIgcGxvdHMNCg0KbXlwbG90PWxpc3QoKQ0KDQpwIDwtIGZ1bmN0aW9uKGRhdGFzZXQpew0KICBqPC0xDQogIGZvciAoaSBpbiA0Om5jb2woZGF0YXNldCkgKXsNCiAgICBwcmludChpKQ0KICAgIG15cGxvdFtbal1dIDwtIGdncGxvdChkYXRhc2V0LCBhZXNfc3RyaW5nKGNvbG5hbWVzKGRhdGFzZXQpWzNdLCBjb2xuYW1lcyhkYXRhc2V0KVtpXSxjb2xvcj0iTGVhZ3VlIikpKw0KICAgICAgZ2VvbV9wb2ludCgpDQogICAgDQogICAgajwtaisxDQogICAgDQogIH0NCiAgDQogIGdyaWQuYXJyYW5nZShncm9icz1teXBsb3QpDQogICMgcmV0dXJuKG15cGxvdCkNCn0NCg0KcChkNCkNCmBgYA0KDQoNCmBgYHtyIGZ4bjJ9DQojIGZ1bmN0aW9uIHRvIHN1Y2Nlc3NpdmVseSBnZXQgcGxvdHMgb2YgVjIgdnMgb3RoZXIgdmFyaWFibGVzDQpteXBsb3QgPC1mdW5jdGlvbihkZiwgeV9zdHJpbmcpew0KICBnZ3Bsb3QoZGYsIGFlc19zdHJpbmcoeCA9ICJWMiIsIHkgPSB5X3N0cmluZywgY29sb3IgPSAiTGVhZ3VlIikpKw0KICAgIGdlb21fcG9pbnQoKSsNCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJibGFjayIpKw0KICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIikNCn0NCmBgYA0KDQpgYGB7cn0NCiMgVmFyaWFibGVzIHRoYXQgc2VlbSB0byBoYXZlIHN0cm9uZ2VzdCBwb3N0aXZlIHJlbGF0aW9uc2hpcA0KIyBIUiBwZXIgZ2FtZToNCm15cGxvdChkNCwgIkhSLnBlci5nYW1lIikNCmBgYA0KDQpgYGB7cn0NCiMgSFINCm15cGxvdChkNCwgIlgzQiIpDQpgYGANCg0KUGVyIHRoZSBwbG90LCBIUiBwZXIgZ2FtZSBhbmQgSFIgaGF2ZSB0aGUgc2FtZSBzY2F0dGVyIHBvaW50cy4gVGhlIHR3byBoYXZlIHN0cm9uZ2VzdCBwb3NpdHZlIGNvbm5lY3Rpb24gdG8gVjIgd2hpbGUgWDNCIGhhcyB0aGUgc3Ryb25nZXN0IG5lZ2F0aXZlIGNvbm5lY3Rpb24gdG8gVjIuDQoNCg==